package org.ns.learn.rpc.client.rpcinterface;

import org.ns.learn.rpc.client.RpcAutowired;
import org.ns.learn.rpc.client.RpcClient;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotatedElementUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class RpcClientBeanProxyManage implements BeanPostProcessor {
    RpcClients clients = new RpcClients();
    Map<String, Object> rpcObjectMap = new ConcurrentHashMap<>();

    public RpcClientBeanProxyManage(RpcClient client) {
        this.clients.add(client);
    }

    public RpcClientBeanProxyManage(RpcClients clients) {
        this.clients = clients;
    }

    public RpcClients getClients() {
        return clients;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class<?> targetClass = AopUtils.getTargetClass(bean);
        List<Field> fields = find(targetClass);
        for (Field field : fields) {
            System.out.println(field);
            Class<?> fieldType = field.getType();
            RpcAutowired rpcAutowired = AnnotatedElementUtils.findMergedAnnotation(field, RpcAutowired.class);
            String value = rpcAutowired.value();
            String rpcBeanName = getBeanName(value, field);
            Object rpcBean = rpcObjectMap.get(rpcBeanName);
            if (rpcBean == null) {
                rpcBean = Proxy.newProxyInstance(fieldType.getClassLoader(), new Class[]{fieldType}, new RpcProxy(clients, rpcBeanName));
                rpcObjectMap.put(rpcBeanName, rpcBean);
            }
            try {
                field.set(bean, rpcBean);
            } catch (Exception e) {
                throw new BeanInitializationException("初始化失败！：" + rpcBeanName + "， bean："+ targetClass, e);
            }

        }
        return bean;
    }

    public String getBeanName(String value , Field field) {
        if (value == null || (value = value.trim()).isEmpty()) {
            return  field.getName();
        }
        return value;
    }

    public List<Field> find(Class<?> targetClass) {
        Class<?> beanType = targetClass;
        List<Field> fields =  new ArrayList<>();
        while (beanType != null && beanType != Object.class) {
            Field[] declaredFields = beanType.getDeclaredFields();
            for (Field field : declaredFields) {
                if (field.getType().isInterface() &&
                        AnnotatedElementUtils.hasAnnotation(field, RpcAutowired.class)) {
                    field.setAccessible(true);
                    fields.add(field);
                }
            }
            beanType = beanType.getSuperclass();
        }
        return fields;
    }
}
